package tsb.dtd;

import java.util.ArrayList;
import java.util.Iterator;
import tsb.util.StrOp;

/**
 *
 * intenta generar un validador dtd.
 */
public class DTDGenerarValidador {

    private DTDValidadorSintaxis validadorSintaxis;
    private DTDValidador validador;
    private ArrayList<String> reglas;
    private boolean commit = false;
    private String reglaConError;

    public DTDGenerarValidador() {
        validadorSintaxis = new DTDValidadorSintaxis();
        validador = new DTDValidador();
        this.reglas = new ArrayList<String>();
        reglaConError = null;
    }

    public synchronized void tryGenerarValidador(final String regla, final boolean esInterna) throws DTDException {
        int tipo = validadorSintaxis.validar(regla);

        switch (tipo) {
            case DTDValidadorSintaxis.ELEMENT:
                validador.addRegla(regla, esInterna, DTDValidadorSintaxis.ELEMENT);
                break;
            case DTDValidadorSintaxis.ATTLIST:
                validador.addRegla(regla, esInterna, DTDValidadorSintaxis.ATTLIST);
                break;
            case DTDValidadorSintaxis.DOC_INFO:
                break;
            case DTDValidadorSintaxis.ERROR:
                throw new DTDException("Sintaxis inválida: " + regla);
            default:
                throw new DTDException("DTD Error");
        }

        this.reglas.add(regla);
    }

    public DTDValidador getDTDValidador() throws DTDException {
        if (!commit) {
            throw new DTDException("El DTDValidador no fue validado.");
        } 
        return this.validador;
    }

    public synchronized boolean commit() throws DTDException{
        commit = true;

        for (Iterator<String> it = reglas.iterator(); commit && it.hasNext();) {
            String regla = it.next();

            if (regla.startsWith("<!ELEMENT")) {
                commit = buscarPadreDeElement(regla);
            }
            else if (regla.startsWith("<!ATTLIST")) {
                commit = buscarPadreDeAttList(regla);
            }
        }

        if(!commit){
            this.reglaConError="Padre no encontrado: " + this.reglaConError;
             throw new DTDException(this.reglaConError);
        }
        return commit;
    }

    private boolean buscarPadreDeAttList(String regla){
        boolean resultado = false;
        String nombre = regla.split(" ")[1].trim();

        for (Iterator<String> it = reglas.iterator(); resultado == false && it.hasNext();) {
            String rElement = it.next();
            if (rElement.startsWith("<!ELEMENT")) {
                String nElement = rElement.split(" ")[1].trim();
                resultado = (nElement.equals(nombre));
            }
        }
        return resultado;
    }

    private boolean buscarPadreDeElement(String regla) {
        boolean resultado = true;
        String nombre = regla.split(" ")[1].trim();
        if (regla.indexOf('(') != -1 && regla.indexOf(')') != -1) {
            String[] lReglas = getListaDeReglasDeComponentes(regla);
            for (int i = 0; resultado == true && i < lReglas.length; i++) {
                String lr = lReglas[i];
                if (lr.equals("#PCDATA") == false) {
                    resultado = (buscarPadreDeReglas(lr, nombre));
                }
            }
        }
        if (!resultado) {
            this.reglaConError += regla;
        }
        return resultado;
    }

    private boolean buscarPadreDeReglas(String nombreBuscado, String nombre) {
        boolean resultado = false;

        for (Iterator<String> it = reglas.iterator(); resultado == false && it.hasNext();) {
            String regla = it.next();
            String aux = regla.split(" ")[1].trim();
            resultado = (regla.startsWith("<!ELEMENT") && aux.equals(nombre) == false && aux.equals(nombreBuscado));
        }
        if (!resultado) {
            this.reglaConError = "\"" + nombreBuscado + "\" ya insertado ";
        }
        return resultado;
    }

    private String[] getListaDeReglasDeComponentes(String regla) {
        ArrayList<String> resultado = new ArrayList<String>();
        String lista = StrOp.separar(regla, " ", "<!ELEMENT", ">", '(', ')')[1];

        if (lista.charAt(lista.length() - 1) != ')') {
            lista = lista.substring(0, lista.length() - 1);
        }

        String[] il = StrOp.separar(lista, ",", "(", ")", '(', ')');

        for (int i = 0; i < il.length; i++) {
            String aux = il[i].trim();
            if (aux.indexOf('|') == -1) {
                resultado.add(aux);
            }
            else {
                String[] il2 = aux.split("[|]");
                for (int j = 0; j < il2.length; j++) {
                    String aux1 = il2[j].trim();
                    resultado.add(aux1);
                }//for
            }//else
        }//for
        return resultado.toArray(new String[resultado.size()]);
    }//get
}
